package minijvm.clz;

import minijvm.constant.ClassInfo;
import minijvm.constant.ConstantPool;
import minijvm.field.Field;
import minijvm.method.Method;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author ChangLiang
 * @date 2020/4/12
 */
public class ClassFile {

    private int minorVersion;
    private int majorVersion;

    private AccessFlag accessFlag;
    private ClassIndex clzIndex;
    private ConstantPool pool;

    private List<Field> fields = new ArrayList<>();
    private List<Method> methods = new ArrayList<>();

    public String getClassName(){
        int thisClassIndex = this.clzIndex.getThisClassIndex();
        ClassInfo thisClass = (ClassInfo)this.getPool().getConstantInfo(thisClassIndex);
        return thisClass.getClassName();
    }
    public String getSuperClassName(){
        ClassInfo superClass = (ClassInfo)this.getPool().getConstantInfo(this.clzIndex.getSuperClassIndex());
        return superClass.getClassName();
    }

    /**
     * 获取main方法
     * @return
     */
    public Method getMainMethod() {
        for (Method method : methods) {
            int nameIndex = method.getNameIndex();
            String name = pool.getUTF8String(nameIndex);
            int descriptorIndex = method.getDescriptorIndex();
            String des = pool.getUTF8String(descriptorIndex);
            if(name.equals("main") && des.equals("([Ljava/lang/String;)V")){
                return method;
            }
        }
        throw new RuntimeException("not found main class");
    }

    public Method getMethod(String methodName, String paramAndReturnType) {
        for (int i = 0; i < methods.size(); i++) {
            Method method = methods.get(i);
            int nameIndex = method.getNameIndex();
            String name = pool.getUTF8String(nameIndex);
            if (!StringUtils.equals(methodName, name)) {
                continue;
            }
            int descriptorIndex = method.getDescriptorIndex();
            String des = pool.getUTF8String(descriptorIndex);
            if (!StringUtils.equals(des, paramAndReturnType)) {
                continue;
            }
            return method;
        }
        return null;
    }


    public void addMethod(Method m){
        this.methods.add(m);
    }
    public List<Method> getMethods() {
        return methods;
    }

    public void addField(Field f) {
        this.fields.add(f);
    }

    public List<Field> getFields() {
        return this.fields;
    }


    public int getMinorVersion() {
        return minorVersion;
    }

    public void setMinorVersion(int minorVersion) {
        this.minorVersion = minorVersion;
    }

    public int getMajorVersion() {
        return majorVersion;
    }

    public void setMajorVersion(int majorVersion) {
        this.majorVersion = majorVersion;
    }

    public AccessFlag getAccessFlag() {
        return accessFlag;
    }

    public void setAccessFlag(AccessFlag accessFlag) {
        this.accessFlag = accessFlag;
    }

    public ClassIndex getClzIndex() {
        return clzIndex;
    }

    public void setClzIndex(ClassIndex clzIndex) {
        this.clzIndex = clzIndex;
    }

    public ConstantPool getPool() {
        return pool;
    }

    public void setPool(ConstantPool pool) {
        this.pool = pool;
    }
}
